/*
	Simple Software Renderer (SSRenderer)
	Copyright (C) 2007 Piotr Orzechowski <piotr.orzechowski@gmail.com>

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef _SSRRENDERER_H
#define _SSRRENDERER_H

#include <memory>
#include "./SSR.h"
#include "./utilities/ErrorStack.h"

namespace ssr
{

/**
	Error messages.
*/
static const char* ERROR_STRINGS[] =
{
	"Couldn't set render target!\0",
	"Rendering target NULL!\0",
	"Color buffer NULL!\0",
	"Rendering target already locked!\0",
	"Rendering target is not locked!\0",
	"Color surface NULL!\0",
};

const int ERROR_STRINGS_COUNT = 5;

/**
	Error messages codes.
*/
static const s32 SSRERR_CSRT	= 0;
static const s32 SSRERR_RTN		= 1;
static const s32 SSRERR_CBN		= 2;
static const s32 SSRERR_RTAL	= 3;
static const s32 SSRERR_RTNL	= 4;
static const s32 SSRERR_CSN	    = 5;

/**
	SSRRenderer is a core class of the library. It is responsible of
	drawing everything you need on a specified rendering target.

	You can have multiple instances of SSRRenderer, each of which
	working on a different (or the same) rendering target.

	The class is a toolkit for raster operations and a pipeline
	for 3D graphics.

	Before using *ANY* drawing operations, user has to invoke
	BeginDrawing() method. When the user finishes drawing
	EndDrawing() has to be called.

	Example :

	pRenderer->BeginDrawing();

        // here goes some drawing ...
        pRenderer->ClearColorBuffer(0xFF0000);
        pRenderer->PutPixel(69, 69, 0x00FFAA);

    pRenderer->EndDrawing();

*/
class SSRRenderer :
	public ISSRObject
{
public:

	/**
		Static method used to create an instance of SSRRenderer.

		Important: CreateRenderer() is the only way of creating
		an instace of SSRRenderer.

		When the object is no longer needed, just call
		SSR_RELEASE(ptr) with a pointer to	the object.

		@return pointer to the newly created SSRRenderer object
	*/
	static SSRRenderer* CreateRenderer()
	{
		return new SSRRenderer();
	}

	/**
		Returns a reference to the error stack of the renderer.

		@return reference to the error stack of the renderer
	*/
	///@todo cholera wie jak przekazywac ten error stack :F cos mi sie z tym nie podoba jeszcze
	util::ErrorStack& GetErrorStack()
	{
		return m_ErrorStack;
	}

	/**
		Sets a new rendering target as a rendering destination.
		Rendering target can only be changed when current rendering
		target is not locked.

		@param target new render target

		@return true on success, false otherwise
	*/
	bool SetRenderTarget(SSRRenderTarget *target);

	/**
        Viewport information is used during 3D rendering.

		As stated in OpenGL 1.1 Documentation :

		SetViewport specifies the affine transformation of x and y from
		normalized device coordinates to window coordinates.

		Let (xnd, ynd) be normalized device coordinates. Then the window
		coordinates (xw, yw) are computed as follows:

		xw = (xnd + 1) * (width / 2) + x
		yw = (ynd + 1) * (height / 2) + y

		Viewport width and height are silently clamped to a range that
		depends on the implementation
	*/
	void SetViewport(u32 x, u32 y, u32 width, u32 height);

	/**
		This method must be called before using any *drawing* operations.
		BeginDrawing() is responsible of preparing rendering target
		for drawing.
	*/
	void BeginDrawing();

	/**
		This method must be called when finishing drawing operations.
	*/
	void EndDrawing();

	/**
		Clears the rendering target with a specified color.

		Important: this method can be only called inside Begin/EndDrawing() block.

		@param color clear color
	*/
	inline void ClearColorBuffer(const color32 &color);

	/**
		Puts a pixel in the current rendering target's color buffer.

		Important: this method can be only called inside Begin/EndDrawing() block.

		@param x x position of the pixel
		@param y y position of the pixel
		@param color color of the pixel
	*/
	inline void PutPixel(u32 x, u32 y, const color32 &color);

	/**
		Blends a pixel in the current rendering target's color buffer with a
		given color (alpha factor = 0.5).

		Important: this method can be only called inside Begin/EndDrawing() block.

		@param x x position of the pixel
		@param y y position of the pixel
		@param color color of the pixel
	*/
	inline void BlendPixel_Alpha_0_5(u32 x, u32 y, const color32 &color);

	/**
		Blends a pixel in the current rendering target's color buffer with a
		given color (alpha factor = 0.25).

		Important: this method can be only called inside Begin/EndDrawing() block.

		@param x x position of the pixel
		@param y y position of the pixel
		@param color color of the pixel
	*/
	inline void BlendPixel_Alpha_0_25(u32 x, u32 y, const color32 &color);

	/**
		Blends a pixel in the current rendering target's color buffer with a
		given color (alpha factor = 0.125).

		Important: this method can be only called inside Begin/EndDrawing() block.

		@param x x position of the pixel
		@param y y position of the pixel
		@param color color of the pixel
	*/
	inline void BlendPixel_Alpha_0_125(u32 x, u32 y, const color32 &color);

	/**
		Gets a pixel color from the current rendering target's color buffer.

		Important: this method can be only called inside Begin/EndDrawing() block.

		@param x x position of the pixel
		@param y y position of the pixel

		@return color of the sampled pixel
	*/
	inline color32 GetPixel(u32 x, u32 y);

	/**
		Returns NULL-ended string containing name of the class.
		Satisfies ISSRObject implementation.

		@return NULL-ended string containing name of the class
	*/
	const u8* ClassName()
	{
		const static u8 name[] = "SSRRenderer\0";
		return name;
	}

protected:

	/**
		Default constructor.
	*/
	SSRRenderer();

	/**
		Virtual destructor.
	*/
	virtual ~SSRRenderer();


	/** Error stack which stores error messages coming from SSRRenderer pipeline */
	util::ErrorStack m_ErrorStack;


	/** Pointer to the current rendering target */
	SSRRenderTarget *m_pTarget;

	/** Pointer to the color surface of the current rendering target */
	SSRSurface *m_pColorSurface;

	/** Pointer to the beginning of the color buffer of the current rendering target */
	color32 *m_pColorBuffer;

	/** Width of a single line in the color buffer */
	u32 m_ColorBufferPitch;


	/** Viewport structure */
	struct viewportinfo
	{
		u32 x, y;
		u32 width, height;
		viewportinfo() : x(0), y(0), width(0), height(0) {}
	} m_Viewport;


private:

};

// Include inline expanded methods
#include "./SSRRenderer.inl"

} // namespace

#endif
